﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Machine.Specifications;
using Infrastructure;
using RegCustomer;
using Moq;

namespace mSpecDemo
{

    public class PublishedEventArgs : EventArgs
    {
        public Event Event { get; set; }
    }

    public class FakePublisher : Infrastructure.IEventPublisher
    {
        public event EventHandler Published;

        public void Publish<T>(T @event) where T : Event
        {
            if (this.Published != null)
            {
                PublishedEventArgs args = new PublishedEventArgs();
                args.Event = @event;
                Published(this, args);
            }
        }

        public void RegisterSubscriber(FakeSubscriber subscriber)
        {
            this.Published += new EventHandler(subscriber.Handle);
        }
    }

    public class FakeSubscriber
    {
        public Dictionary<String, Event> HandledEvents { get; private set; }

        public FakeSubscriber()
        {
            HandledEvents = new Dictionary<string, Event>();
        }

        public void Handle(object sender, EventArgs eventArgs)
        {
            HandledEvents.Add(((PublishedEventArgs)eventArgs).Event.ToString(), 
                                ((PublishedEventArgs)eventArgs).Event);
        }
    }

    [Subject("Test")]
    public class When_Submitting_A_Create_Customer_Commands
    {

        protected static CreateNewCustomerCommand _createNewCustomer;
        protected static UpdateCustomerCommand _updateNewCustomer;
        protected static DeactivateCustomerCommand _invalidateCustomerCommand;

        protected static string _name = "Sean";
        protected static Guid _id;

        protected static Repository<Customer> _repository;
        protected static EventStore _eventStore;
        protected static Mock<IEventPublisher> _publisher;
        protected static CommandHandlers _handlers;
        protected static FakeBus _bus = new FakeBus();
        private static FakeSubscriber _subscriber;

        private static List<Customer> _stateMachine = new List<Customer>();
        protected static int _version;

        static string _newName = "NewSeanName";
        
        Establish context = () =>
            {

                _publisher = new Mock<IEventPublisher>();
                var _fakePublisher = new FakePublisher();
                _eventStore = new EventStore(_fakePublisher);
                _repository = new Repository<Customer>(_eventStore);
                _handlers = new CommandHandlers(_repository);

                _subscriber = new FakeSubscriber();

                _id = Guid.NewGuid();
                _version = 0;

                _bus.RegisterHandler<CreateNewCustomerCommand>(_handlers.Handle);                
                _createNewCustomer = new CreateNewCustomerCommand(_id, _name, _version);
                _fakePublisher.RegisterSubscriber(_subscriber);

            };

        Because of = () =>
            {
                _bus.Send(_createNewCustomer);
                _version++;
            };

        Machine.Specifications.It should_create_a_customer = () =>
            {
                _repository.GetById(_id).Id.ShouldEqual(_id);
            };

        Machine.Specifications.It should_publish_a_customer_Created_event = () =>
            {
                _subscriber.HandledEvents.Count.ShouldEqual(1);
                _subscriber.HandledEvents.First().Value.ShouldBeOfType(typeof(CustomerCreatedEvent));
            };

        Cleanup Clear_Context = () => _subscriber.HandledEvents.Clear();


    }

}
